package com.adcc.ags.msgStore.service;

import com.adcc.ags.msgStore.common.Constant;
import com.adcc.ags.msgStore.dao.MsgStoreDao;
import com.adcc.ags.msgStore.dao.MsgStoreDaoImpl;
import com.adcc.ags.msgStore.entity.db.DBErrorCode;
import com.adcc.ags.msgStore.entity.db.DBInfo;
import com.adcc.ags.msgStore.entity.db.DBMessage;
import com.adcc.ags.msgStore.entity.db.DBState;
import com.adcc.utility.log.Log;
import com.adcc.utility.mq.entity.Message;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Optional;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by ZHANG on 2016/11/21.
 */
public class MsgStoreInOrderServiceImpl extends MsgStoreInOrderService {
    private MsgStoreDao msgStoreDao = MsgStoreDaoImpl.getInstance();

    /**
     * 保存报文到oracle数据库中
     * @param message
     */
    @Override
    public DBErrorCode saveMessage(String message) {
        Optional<DBMessage> dbMessage = changeMQMsgToDBMsg(message);
        if(dbMessage.isPresent()){
            return msgStoreDao.saveDBMessage(dbMessage.get());
        }else{
            return DBErrorCode.CONVERSION_ERROR;
        }
    }

    /**
     * 更新oracle数据库中的报文信息
     * @param message
     * @return
     */
    @Override
    public DBErrorCode updateMessage(String message) {
        Optional<DBMessage> dbMessage = changeMQMsgToDBMsg(message);
        if(dbMessage.isPresent()){
            return msgStoreDao.updateDBMessage(dbMessage.get());
        }else{
            return DBErrorCode.CONVERSION_ERROR;
        }
    }

    /**
     * 保存或更新message
     * @param message
     * @return
     */
    @Override
    public DBErrorCode saveOrUpdateMessage(String message) {
        Optional<DBMessage> dbMessage = changeMQMsgToDBMsg(message);
        Map<String,Object> map=msgStoreDao.isExit(dbMessage.get().getMsgId());
        DBErrorCode errorCode = DBErrorCode.NO_ERROR;
        if(map.get(Constant.IS_EXIT_KEY)!=null){
            if((boolean)map.get(Constant.IS_EXIT_KEY) == true){
                errorCode = updateMessage(message);
            }else if((boolean)map.get(Constant.IS_EXIT_KEY) == false){
                errorCode = saveMessage(message);
            }
        }else {
            errorCode = (DBErrorCode)map.get(Constant.ERROR_CODE_KEY);
        }
        return  errorCode;
    }

    /**
     * 将获取的MQ信息转换成DBMessage实体信息
     * @param message
     * @return
     */
    public Optional<DBMessage> changeMQMsgToDBMsg(String message){
        try {
            Map<String,String> map = new ObjectMapper().readValue(message,HashMap.class);
            DBMessage dbMessage = new DBMessage();
            dbMessage.setDatetime(new Date());
            dbMessage.setMsgType(map.get(Constant.TRAFFIC_MSGTYPE_KEY));
            dbMessage.setReceiver(map.get(Constant.TRAFFIC_RECEIVER_KEY));
            dbMessage.setSender(map.get(Constant.TRAFFIC_SENDER_KEY));
            dbMessage.setState(map.get(Constant.TRAFFIC_STATE_KEY));
            dbMessage.setErrorCode(map.get(Constant.TRAFFIC_ERROR_CODE_KEY));
            dbMessage.setMsgId(map.get(Constant.TRAFFIC_MSGID_KEY));
            dbMessage.setErrorUserId(map.get(Constant.TRAFFIC_ERROR_USER_ID_KEY));
            String rawMsg = map.get(Constant.TRAFFIC_RAWMSG_KEY) == null ? "":map.get(Constant.TRAFFIC_RAWMSG_KEY);
            String part1 = "";
            String part2 = "";
            String part3 = "";
            String part4 = "";
            String part5 = "";
            if (rawMsg.length() > Constant.MESSAGE_SPLIT) {
                switch ((rawMsg.length() / Constant.MESSAGE_SPLIT)) {
                    //If content's length between 4001 and 8000,split it to two parts.
                    case 1:
                        part1 = rawMsg.substring(Constant.MESSAGE_SPLIT);
                        break;
                    //If content's length between 8001 and 12000,split it to three parts.
                    case 2:
                        part1 = rawMsg.substring(Constant.MESSAGE_SPLIT, Constant.MESSAGE_SPLIT * 2);
                        part2 = rawMsg.substring(Constant.MESSAGE_SPLIT * 2);
                        break;
                    //If content's length between 12001 and 16000,split it to four parts.
                    case 3:
                        part1 = rawMsg.substring(Constant.MESSAGE_SPLIT, Constant.MESSAGE_SPLIT * 2);
                        part2 = rawMsg.substring(Constant.MESSAGE_SPLIT * 2, Constant.MESSAGE_SPLIT * 3);
                        part3 = rawMsg.substring(Constant.MESSAGE_SPLIT * 3);
                        break;
                    //If content's length between 16001 and 20000,split it to five parts.
                    case 4:
                        part1 = rawMsg.substring(Constant.MESSAGE_SPLIT, Constant.MESSAGE_SPLIT * 2);
                        part2 = rawMsg.substring(Constant.MESSAGE_SPLIT * 2, Constant.MESSAGE_SPLIT * 3);
                        part3 = rawMsg.substring(Constant.MESSAGE_SPLIT * 3, Constant.MESSAGE_SPLIT * 4);
                        part4 = rawMsg.substring(Constant.MESSAGE_SPLIT * 4);
                        break;
                    //If content's length between 20001 and 24000,split it to six parts.
                    case 5:
                        part1 = rawMsg.substring(Constant.MESSAGE_SPLIT, Constant.MESSAGE_SPLIT * 2);
                        part2 = rawMsg.substring(Constant.MESSAGE_SPLIT * 2, Constant.MESSAGE_SPLIT * 3);
                        part3 = rawMsg.substring(Constant.MESSAGE_SPLIT * 3, Constant.MESSAGE_SPLIT * 4);
                        part4 = rawMsg.substring(Constant.MESSAGE_SPLIT * 4, Constant.MESSAGE_SPLIT * 5);
                        part5 = rawMsg.substring(Constant.MESSAGE_SPLIT * 5);
                        break;
                    //If content's length is 24000,split it to six parts.
                    default:
                        part1 = rawMsg.substring(Constant.MESSAGE_SPLIT, Constant.MESSAGE_SPLIT * 2);
                        part2 = rawMsg.substring(Constant.MESSAGE_SPLIT * 2, Constant.MESSAGE_SPLIT * 3);
                        part3 = rawMsg.substring(Constant.MESSAGE_SPLIT * 3, Constant.MESSAGE_SPLIT * 4);
                        part4 = rawMsg.substring(Constant.MESSAGE_SPLIT * 4, Constant.MESSAGE_SPLIT * 5);
                        part5 = rawMsg.substring(Constant.MESSAGE_SPLIT * 5);
                        break;
                }
                //Put message content from 1 to 4000(if message content's length is less than 4000,end at the last character) into RawMsg.
                dbMessage.setRawMsg(rawMsg.substring(0, Constant.MESSAGE_SPLIT));
                dbMessage.setPart1(part1);
                dbMessage.setPart2(part2);
                dbMessage.setPart3(part3);
                dbMessage.setPart4(part4);
                dbMessage.setPart5(part5);
            } else {
                //If message content's length is less than 4000,put it all into RAWMSG of DB.
                dbMessage.setRawMsg(rawMsg);
            }
            //If message content's length is bigger than 24000,give a message to remind length is more than max.
            if (rawMsg.length() > Constant.MESSAGE_SPLIT * 6) {
                part5 = part5.substring(Constant.MESSAGE_SPLIT * 5, (Constant.MESSAGE_SPLIT * 6 - 41));
                part5 += "!!!message length is more than 24000!!!";
                dbMessage.setPart5(part5);
            }
            return Optional.of(dbMessage);
        } catch (IOException e) {
            Log.error(MsgStoreInOrderServiceImpl.class.getName(), "changeMQMsgToDBMsg() error", e);
            return Optional.absent();
        }
    }

    @Override
    public void onReceive(Object message) throws Exception {
        if(message == null){
            Log.error(MsgStoreInOrderServiceImpl.class.getName(), "receive message is null");
            unhandled(message);
        }else{
            if(message instanceof Message){
                Message msg = (Message)message;
                DBErrorCode flag = saveOrUpdateMessage(message.toString());
                if (flag == DBErrorCode.CONNECT_ERROR) {
                    Log.error(MsgStoreInOrderServiceImpl.class.getName(), "connect to database failed!");
                    DBInfo.getInstance().setState(DBState.CONNECTING);
                } else if(flag == DBErrorCode.SEND_ERROR) {
                    Log.error(MsgStoreInOrderServiceImpl.class.getName(), "save message to oracle error!\r\n"+message);
                } else if(flag == DBErrorCode.UPDATE_ERROR) {
                    Log.error(MsgStoreInOrderServiceImpl.class.getName(), "update message to oracle error!\r\n"+message);
                }
            }
        }
    }
}
